/*
 * epoll.c
 *
 *  Created on: 03/11/2011
 *      Author: Normandia
 */


#include "epoll.h"


void crearServer_epoll(void (*fun_lectura)(),void (*fun_termina)(), int puerto) {
	struct epoll_event ev, *events;
	int listen_sock, conn_sock, nfds;
	struct sockaddr_in *myAddr;
	struct in_addr ip;
	uint8_t n;

	/* Crea el socket de escucha de conexiones */
	listen_sock = mksocket(SERVER,ip,puerto,myAddr);
	

	// Crea el epoll
	epollfd = epoll_create(MAX_CONEXIONES);
	if (epollfd == -1) {
	   perror("epoll_create");
	}

	// Crea el evento para el socket de escucha
	ev.events = EPOLLIN;
	ev.data.fd = listen_sock;
	if (epoll_ctl(epollfd, EPOLL_CTL_ADD, listen_sock, &ev) == -1) {
	   perror("epoll_ctl: listen_sock");
	}

	events = malloc(MAX_CONEXIONES * sizeof(struct epoll_event));

	while(1) {
	   nfds = epoll_wait(epollfd, events, MAX_CONEXIONES, -1);
	   if (nfds == -1) {
		   perror("epoll_pwait");
	   }

	   for (n = 0; n < nfds; ++n) {
		   if (events[n].data.fd == listen_sock) {
			   conn_sock = accept(listen_sock,NULL,NULL);
			   if (conn_sock == -1) {
				   perror("accept");
			   }

			   /*if(fcntl(conn_sock, F_SETFL, O_NONBLOCK)){
				   perror("fcntl");
			   }*/

			   ev.events = EPOLLIN;
			   ev.data.fd = conn_sock;
			   if (epoll_ctl(epollfd, EPOLL_CTL_ADD, conn_sock,&ev) == -1) {
				   perror("epoll_ctl: conn_sock");
			   }
			//printf("Aceptado socket\n");
		   } else {
			//printf("Leyendo socket\n");
			   fun_lectura(events[n].data.fd);
		   }
	   }
	   if(fun_termina)
		   fun_termina();
	}
}

void quitarSocket_epoll(int socket){

	if (epoll_ctl(epollfd, EPOLL_CTL_DEL, socket, NULL) == -1) {
	   perror("epoll_ctl: listen_sock");
	}

}

void crearCliente_epoll(void (*fun_lectura)(int), int (*fun_handshake)(int),  struct in_addr ip, int puerto) {

	struct sockaddr_in *myAddr;
	int handshake_rta;
	struct epoll_event ev, *events;
	int conn_sock, nfds;
	uint8_t n;

	//Crea el epoll
	/*epollfd = epoll_create(MAX_CONEXIONES);
	if (epollfd == -1) {
	   perror("epoll_create");
	}

	events = malloc(MAX_CONEXIONES * sizeof(struct epoll_event));
*/
	/* Crea el socket de escucha de conexiones */
	/*listen_sock = mksocket(SERVER,ip,puerto,myAddr);

	conn_sock = accept(listen_sock,NULL,NULL);
	if (conn_sock == -1) {
	   perror("accept");
	}

	if(fcntl(conn_sock, F_SETFL, O_NONBLOCK)){
	   perror("fcntl");
	}

	ev.events = EPOLLIN | EPOLLET;
	ev.data.fd = conn_sock;
	if (epoll_ctl(epollfd, EPOLL_CTL_ADD, conn_sock,&ev) == -1) {
		perror("epoll_ctl: conn_sock");
	}

	close(listen_sock);
*/
	conn_sock = mksocket(CLIENT, ip, puerto, myAddr);

	if(!conn_sock)
		perror("mksocket");

	handshake_rta = fun_handshake(conn_sock);

	if(handshake_rta){
		close(conn_sock);
		exit(0);
	}

	/*ev.events = EPOLLIN | EPOLLET;
	ev.data.fd = conn_sock;
	if (epoll_ctl(epollfd, EPOLL_CTL_ADD, conn_sock,&ev) == -1) {
		perror("epoll_ctl: conn_sock");
	}*/
	while(1){
		fun_lectura(conn_sock);
		/*nfds = epoll_wait(epollfd, events, MAX_CONEXIONES, -1);
		if (nfds == -1) {
			perror("epoll_pwait");
		}

		for (n = 0; n < nfds; ++n) {
			//printf("Leyendo socket\n");
			fun_lectura(events[n].data.fd);
		}*/
	}

}
/*	// Crea el epoll
	epollfd = epoll_create(MAX_CONEXIONES);
	if (epollfd == -1) {
	   perror("epoll_create");
	}

	// Crea el evento para el write
	ev.events = EPOLLIN | EPOLLET;
	ev.data.fd = conn_sock;
	if (epoll_ctl(epollfd, EPOLL_CTL_ADD, conn_sock, &ev) == -1) {
	   perror("epoll_ctl: cliente %u");
	}

	// Conecta los n sockets
	for (n = 1;n<cant_conexiones;n++) {

		conn_sock = mksocket(CLIENT, ip, htons(puerto++), myAddr);

		if(fcntl(conn_sock, F_SETFL, O_NONBLOCK)){
			perror("fcntl");
		}

		// Crea el evento para el write
		ev.events = EPOLLIN | EPOLLET;
		ev.data.fd = conn_sock;
		if (epoll_ctl(epollfd, EPOLL_CTL_ADD, conn_sock, &ev) == -1) {
		   perror("epoll_ctl: cliente %u");
		}
	}

	events = malloc(sizeof(struct epoll_event) * cant_conexiones);

	while(1) {
	   nfds = epoll_wait(epollfd, events, MAX_CONEXIONES, -1);
	   printf("Deja de esperar\n");
	   if (nfds == -1) {
		   perror("epoll_pwait");
	   }

	   for (n = 0; n < nfds; n++) {
		   fun_lectura(events[n].data.fd);
	   }

	}*/

/*
void crearCliente_send_epoll(void (*fun_escritura)(int), uint8_t cant_conexiones) {
	struct epoll_event ev, *events;
	int conn_sock, nfds, epollfd;
	struct sockaddr_in *myAddr;
	uint8_t n;
	socklen_t addrlen;
	int yes=1;

	// Conecta los n sockets
	for (n = 0;n<cant_conexiones;n++) {

		if ((conn_sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
			perror("socket cliente");

		if (setsockopt(conn_sock,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int))<0){
			perror("setsockopt cliente");
		}

		// Crea el epoll

		epollfd = epoll_create(MAX_CONEXIONES);
		if (epollfd == -1) {
		   perror("epoll_create");
		}

		// Crea el evento para el write
		ev.events = EPOLLOUT | EPOLLONESHOT; // EPOLLONESHOT para que el socket no pueda volver a ser usado
											 // hasta no hacer un recv
		ev.data.fd = conn_sock;
		if (epoll_ctl(epollfd, EPOLL_CTL_ADD, conn_sock, &ev) == -1) {
		   perror("epoll_ctl: cliente %u",n);
		}

	}


	while(1) {
		nfds = epoll_wait(epollfd, events, cant_conexiones, -1);
		if (nfds == -1) {
			perror("epoll_pwait");
		}

		for (n = 0; n < nfds; ++n) {
			fun_escritura(events[n].data.fd);
			// Vuelve a poner el evento al socket
		}
	}
}
*/
